﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;

namespace DTOTemplatedGenerator.Utils
{
    public class DragAndDropDataGridRows
    {
        private DataGrid _grid;
        private IList _list;
        private int _rowIndex = -1;
        private bool _isDragging;
        private List<object> _selectedItems;


        public DragAndDropDataGridRows(DataGrid grid)
        {
            _grid = grid;
            _grid.AllowDrop = true;
            grid.PreviewMouseLeftButtonDown += (s, e) =>
                                                   {
                                                       Trace.WriteLine(e.OriginalSource.GetType());                                                       
                                                       _grid.PreviewMouseMove -= _grid_PreviewMouseMove;
                                                       _list = grid.ItemsSource as IList;
                                                       if(_list == null)
                                                           return;
                                                       _selectedItems = _grid.SelectedItems.OfType<object>().ToList();
                                                       if (_selectedItems.Count == 1)
                                                       {
                                                           var ind = getCurrentRowIndex(e.GetPosition);
                                                           
                                                           if (ind >= 0 && 
                                                               _list.IndexOf(_selectedItems[0]) != ind &&
                                                               _list.Count > ind)
                                                               _selectedItems = new List<object>() {_list[ind]};                                                           
                                                       }
                                                       _grid.PreviewMouseMove += _grid_PreviewMouseMove;
                                                   };
            //_grid.PreviewMouseLeftButtonDown += (s, e) =>
            //{
            //    _list = grid.ItemsSource as IList;
            //    _rowIndex = getCurrentRowIndex(e.GetPosition);
            //    if (_rowIndex < 0)
            //        return;
            //    _grid.SelectedIndex = _rowIndex;
            //    var selectedEmp = _grid.Items[_rowIndex];
            //    if (selectedEmp == null)
            //        return;

            //    if (DragDrop.DoDragDrop(_grid, selectedEmp, DragDropEffects.Move)
            //                        != DragDropEffects.None)
            //    {
            //        _grid.SelectedItem = selectedEmp;
            //    }
            //};
            _grid.Drop += (s, e) =>
            {
                if (_list == null)
                    return;
                _list = grid.ItemsSource as IList;
                //if (_rowIndex < 0)
                //    return;
                int index = this.getCurrentRowIndex(e.GetPosition);
                if (index < 0)
                    return;
                if (index == _rowIndex)
                    return;
                if (index == _grid.Items.Count - 1)
                {
                    MessageBox.Show("Wrong row-index to drop");
                    return;
                }

                if (_selectedItems.Count == 0)
                    return;
                for (int i = 0; i < _selectedItems.Count; i++)
                {
                    var ind = _list.IndexOf(_selectedItems[i]);
                    if(ind < 0)
                        continue;
                    _list.RemoveAt(ind);
                    _list.Insert(index, _selectedItems[i]);
                    if (index < ind)
                        index++;
                }
            };
        }

        void _grid_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && 
                e.OriginalSource is TextBox == false &&
                e.OriginalSource is DataGridColumnHeader == false &&
                e.OriginalSource is Thumb == false)
            {
                if (_isDragging)
                    return;
                _list = _grid.ItemsSource as IList;
                _rowIndex = getCurrentRowIndex(e.GetPosition);
                if (_rowIndex < 0)
                    return;
                //_grid.SelectedIndex = _rowIndex;
                var selectedEmp = _grid.Items[_rowIndex];
                if (selectedEmp == null)
                    return;

                try
                {
                    if(DragDrop.DoDragDrop(_grid, selectedEmp, DragDropEffects.Move)
                        != DragDropEffects.None)
                    {
                        _grid.SelectedItem = selectedEmp;
                    }
                    _isDragging = true;
                }
                catch (Exception ex)
                {
                    return;
                }
            }
            else
            {
                _isDragging = false;
                _grid.PreviewMouseMove -= _grid_PreviewMouseMove;
            }
        }

        private int getCurrentRowIndex(Func<IInputElement, Point> pos)
        {
            int curIndex = -1;
            for (int i = 0; i < _grid.Items.Count; i++)
            {
                DataGridRow itm = getRowItem(i);
                if(itm == null)
                    continue; 
                if (getMouseTargetRow(itm, pos))
                {
                    curIndex = i;
                    break;
                }
            }
            return curIndex;
        }

        private bool getMouseTargetRow(Visual theTarget, Func<IInputElement, Point> position)
        {
            Rect rect = VisualTreeHelper.GetDescendantBounds(theTarget);
            Point point = position((IInputElement)theTarget);
            return rect.Contains(point);
        }

        private DataGridRow getRowItem(int index)
        {
            if (_grid.ItemContainerGenerator.Status
                    != GeneratorStatus.ContainersGenerated)
                return null;
            return _grid.ItemContainerGenerator.ContainerFromIndex(index)
                                                            as DataGridRow;
        }
    }
}
